package com.guxingke.gsb.io;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedWriter;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.ArrayList;
import java.util.List;

/**
 * 文件io.
 *
 * @author guxingke
 * @since 2015/11/24
 */
public class FileAccess {
    private static final Logger logger = LoggerFactory.getLogger(FileAccess.class);

    /**
     * 在basePath目录下写content内容到filename文件中。
     *
     * @param basePath 根路径，必须为有效目录
     * @param fileName 文件名
     * @param content  待写入的内容
     * @throws Exception
     */
    public boolean write(Path basePath, String fileName, String content) {
        if (Files.notExists(basePath)) {
            try {
                Files.createDirectory(basePath);
            } catch (IOException e) {
                logger.error("create directory failed，path:{}", basePath, e);
            }
        }

        try (BufferedWriter bw = Files.newBufferedWriter(basePath.resolve(fileName), StandardCharsets.UTF_8)) {
            bw.write(content);
        } catch (IOException ex) {
            logger.error("write file error,basePath:{},fileName:{}", new Object[]{basePath, fileName}, ex);
            return false;
        }
        return true;
    }

    /**
     * 获取rootPath目录下所有文件名以fileSuffix结尾的文件Path.
     *
     * @param rootPath            待爬取的根路径。
     * @param fileSuffix          文件名后缀
     * @param isParseSubDirectory 是否爬取子目录。
     * @return List:Path.
     * @throws IOException
     */
    public List<Path> parsePathFromDirectory(Path rootPath, String fileSuffix, boolean isParseSubDirectory) throws IOException {
        List<Path> result = new ArrayList<>();
        Files.walkFileTree(rootPath, new FileVisitor<Path>() {
            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                if (!isParseSubDirectory && !dir.endsWith(rootPath)) {
                    return FileVisitResult.SKIP_SUBTREE;
                }
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                if (file.toString().endsWith("." + fileSuffix)) {
                    result.add(file);
                }
                return FileVisitResult.CONTINUE;
            }

            @Override
            public FileVisitResult visitFileFailed(Path file, IOException exc) throws IOException {
                return FileVisitResult.TERMINATE;
            }

            @Override
            public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                return FileVisitResult.CONTINUE;
            }
        });
        return result;
    }

    public boolean copyDirectory(Path source, Path destination) {
        try {
            if (Files.notExists(destination)) {
                Files.createDirectory(destination);
            }
            Files.walkFileTree(source, new SimpleFileVisitor<Path>() {

                @Override
                public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs)
                        throws IOException {
                    Path correspondingOutputPath = destination.resolve(source.relativize(dir));
                    if (Files.notExists(correspondingOutputPath)) {
                        Files.createDirectory(correspondingOutputPath);
                    }

                    return FileVisitResult.CONTINUE;
                }

                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                    Path resolvedPath = destination.resolve(source.relativize(file));

                    Files.copy(file, resolvedPath, StandardCopyOption.REPLACE_EXISTING);

                    return FileVisitResult.CONTINUE;
                }

            });
        } catch (IOException e) {
            logger.error("copy resources failed:source:{},destination:{}", new Object[]{source, destination}, e);
            return false;
        }
        return true;
    }

    public boolean cleanDirectory(Path path, boolean removeGitDir) {
        try {
            Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
                @Override
                public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
                    if (dir.endsWith(".git")){
                        return FileVisitResult.SKIP_SUBTREE;
                    }
                    return FileVisitResult.CONTINUE;
                }

                @Override
                public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
                    Files.delete(file);
                    return FileVisitResult.CONTINUE;
                }

                @Override
                public FileVisitResult postVisitDirectory(Path dir, IOException exc) throws IOException {
                    if (!dir.equals(path)) {
                        Files.delete(dir);
                    }
                    return FileVisitResult.CONTINUE;
                }
            });
        } catch (IOException e) {
            logger.error("clean directory failed:path:{}", path, e);
            return false;
        }
        return true;
    }
}
